/* * The MIT License * * Copyright 2010 Sony Ericsson Mobile Communications. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonyericsson.rebuild; import com.gargoylesoftware.htmlunit.WebAssert; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.Extension; import hudson.model.AbstractBuild; import hudson.model.Action; import hudson.model.Build; import hudson.model.ParameterValue; import hudson.model.Cause; import hudson.model.CauseAction; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import hudson.model.ParametersAction; import hudson.model.ParametersDefinitionProperty; import hudson.model.Project; import hudson.model.StringParameterDefinition; import hudson.model.StringParameterValue; import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.TestExtension; import org.kohsuke.stapler.DataBoundConstructor; import java.io.IOException; import java.util.List; import java.util.concurrent.ExecutionException; /** * For testing the extension point. * * @author Gustaf Lundh <gustaf.lundh@sonyericsson.com> */ public class RebuildValidatorTest extends HudsonTestCase { /** * Sleep delay value. */ public static final int DELAY = 100; /** * Tests with no extensions. * * @throws IOException * IOException * @throws InterruptedException * InterruptedException * @throws ExecutionException * ExecutionException */ public void testNoRebuildValidatorExtension() throws IOException, InterruptedException, ExecutionException { Project projectA = createFreeStyleProject("testFreeStyleA"); Build buildA = (Build) projectA.scheduleBuild2( 0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("party", "megaparty"))).get(); assertNotNull(buildA.getAction(RebuildAction.class)); } /** * Tests with an extension returning isApplicable true. * * @throws IOException * IOException * @throws InterruptedException * InterruptedException * @throws ExecutionException * ExecutionException */ public void testRebuildValidatorExtensionIsApplicableTrue() throws IOException, InterruptedException, ExecutionException { hudson.getExtensionList(RebuildValidator.class).add(0, new ValidatorAlwaysApplicable()); Project projectA = createFreeStyleProject("testFreeStyleB"); Build buildA = (Build) projectA.scheduleBuild2( 0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("party", "megaparty"))).get(); assertNull(buildA.getAction(RebuildAction.class)); } /** * Tests with an extension returning isApplicable false. * * @throws IOException * IOException * @throws InterruptedException * InterruptedException * @throws ExecutionException * ExecutionException */ public void testRebuildValidatorExtensionIsApplicableFalse() throws IOException, InterruptedException, ExecutionException { hudson.getExtensionList(RebuildValidator.class).add(0, new ValidatorNeverApplicable()); Project projectA = createFreeStyleProject("testFreeStyleC"); Build buildA = (Build) projectA.scheduleBuild2( 0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("party", "megaparty"))).get(); assertNotNull(buildA.getAction(RebuildAction.class)); } /** * Tests with two extensions returning isApplicable true AND false. * * @throws IOException * IOException * @throws InterruptedException * InterruptedException * @throws ExecutionException * ExecutionException */ public void testRebuildValidatorExtensionIsApplicableTrueFalse() throws IOException, InterruptedException, ExecutionException { hudson.getExtensionList(RebuildValidator.class).add(0, new ValidatorAlwaysApplicable()); hudson.getExtensionList(RebuildValidator.class).add(0, new ValidatorNeverApplicable()); Project projectA = createFreeStyleProject("testFreeStyleC"); Build buildA = (Build) projectA.scheduleBuild2( 0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("party", "megaparty"))).get(); assertNull(buildA.getAction(RebuildAction.class)); } /** * Creates a new freestyle project and checks if the rebuild action is * available on the project level. * * @throws Exception * Exception */ public void testWhenProjectWithoutParamsThenRebuildProjectAvailable() throws Exception { FreeStyleProject project = createFreeStyleProject(); FreeStyleBuild build = project.scheduleBuild2(0).get(); RebuildLastCompletedBuildAction action = build.getProject().getAction( RebuildLastCompletedBuildAction.class); assertNotNull(action); } /** * Creates a new freestyle project and builds the project with a string * parameter. If the build is succesful, a rebuild of the last build is * done. The rebuild on the project level should point to the last build * * @throws Exception * Exception */ public void testWhenProjectWithNoParamsDefinedThenRebuildofBuildWithParamsShouldShowParams() throws Exception { FreeStyleProject project = createFreeStyleProject(); // Build (#1) project.scheduleBuild2(0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("name", "ABC"))) .get(); HtmlPage rebuildConfigPage = createWebClient().getPage(project, "1/rebuild"); WebAssert.assertElementPresentByXPath(rebuildConfigPage, "//div[@name='parameter']/input[@value='ABC']"); } /** * Creates a new freestyle project and builds the project with a string * parameter. If the build is succesful, a rebuild of the last build is * done. The rebuild on the project level should point to the last build * * @throws Exception * Exception */ public void testWhenProjectWithParamsThenRebuildProjectExecutesRebuildOfLastBuild() throws Exception { FreeStyleProject project = createFreeStyleProject(); project.addProperty(new ParametersDefinitionProperty( new StringParameterDefinition("name", "defaultValue"))); // Build (#1) project.scheduleBuild2(0, new Cause.UserIdCause(), new ParametersAction(new StringParameterValue("name", "test"))) .get(); HtmlPage rebuildConfigPage = createWebClient().getPage(project, "1/rebuild"); // Rebuild (#2) submit(rebuildConfigPage.getFormByName("config")); HtmlPage projectPage = createWebClient().getPage(project); WebAssert.assertLinkPresentWithText(projectPage, "Rebuild Last"); HtmlAnchor rebuildHref = projectPage.getAnchorByText("Rebuild Last"); assertEquals("Rebuild Last should point to the second build", "/" + project.getUrl() + "lastCompletedBuild/rebuild", rebuildHref.getHrefAttribute()); } /** * Creates a new freestyle project and rebuild. Check that the RebuildCause * has been set to the new build. Check also that a UserIdCause is added. * * @throws Exception * Exception */ public void testWhenProjectWithCauseThenCauseIsCopiedAndUserCauseAdded() throws Exception { FreeStyleProject project = createFreeStyleProject(); project.addProperty(new ParametersDefinitionProperty( new StringParameterDefinition("name", "defaultValue"))); // Build (#1) project.scheduleBuild2(0, new Cause.RemoteCause("host", "note"), new ParametersAction(new StringParameterValue("name", "test"))) .get(); HtmlPage rebuildConfigPage = createWebClient().getPage(project, "1/rebuild"); // Rebuild (#2) submit(rebuildConfigPage.getFormByName("config")); createWebClient().getPage(project).getAnchorByText("Rebuild Last") .click(); while (project.isBuilding()) { Thread.sleep(DELAY); } List<Action> actions = project.getLastCompletedBuild().getActions(); boolean hasRebuildCause = false; boolean hasRemoteCause = false; boolean hasUserIdCause = false; for (Action action : actions) { if (action instanceof CauseAction) { CauseAction causeAction = (CauseAction) action; if (causeAction.getCauses().get(0).getClass() .equals(RebuildCause.class)) { hasRebuildCause = true; } if (causeAction.getCauses().get(0).getClass() .equals(Cause.RemoteCause.class)) { hasRemoteCause = true; } if (causeAction.getCauses().get(0).getClass() .equals(Cause.UserIdCause.class)) { hasUserIdCause = true; } } } assertTrue("Build should have user, remote and rebuild causes", hasRebuildCause && hasRemoteCause && hasUserIdCause); } /** * Creates a new freestyle project, builds it and ensures the rebuild action * is available on the project level. * * @throws Exception * Exception */ public void testWhenProjectWithoutParamsThenRebuildProjectEnabled() throws Exception { FreeStyleProject project = createFreeStyleProject(); project.scheduleBuild2(0); RebuildSettings settings = new RebuildSettings(false, false); project.addProperty(settings); project.save(); HtmlPage projectPage = createWebClient().getPage(project); WebAssert.assertLinkPresentWithText(projectPage, "Rebuild Last"); } /** * Creates a new freestyle project, builds it and ensures the rebuild action * isn't available on the project level. * * @throws Exception * Exception */ public void testWhenProjectWithoutParamsThenRebuildProjectIsDisabled() throws Exception { FreeStyleProject project = createFreeStyleProject(); project.scheduleBuild2(0); RebuildSettings settings = new RebuildSettings(false, true); project.addProperty(settings); project.save(); HtmlPage projectPage = createWebClient().getPage(project); WebAssert.assertLinkNotPresentWithText(projectPage, "Rebuild Last"); } /** * Implementing an Extension always returning isApplicable false. */ public static class ValidatorNeverApplicable extends RebuildValidator { @Override public boolean isApplicable(AbstractBuild build) { return false; } } /** * Implementing an Extension always returning isApplicable true. */ public static class ValidatorAlwaysApplicable extends RebuildValidator { @Override public boolean isApplicable(AbstractBuild build) { return true; } } /** * Creates a new freestyle project and build with a parameter value whose * type is unknown to rebuild plugin. Rebuild and verify that an no * exception occurs and page is displayed correctly. * * {@link RebuildableParameterValue}. * * @throws Exception * Exception */ public void testRebuildUnsupportedUnknownParameterValue() throws Exception { WebClient wc = createWebClient(); FreeStyleProject project = createFreeStyleProject(); project.addProperty(new ParametersDefinitionProperty( new UnsupportedUnknownParameterDefinition("param1", "defaultValue"))); assertBuildStatusSuccess(project.scheduleBuild2(0, new Cause.RemoteCause("host", "note"), new ParametersAction(new UnsupportedUnknownParameterValue( "param1", "value1")))); FreeStyleBuild build = project.getLastBuild(); // it is trying to fallback and use the HtmlPage page = wc.getPage(build, "rebuild"); // Check the hardcoded description is showing properly. assertTrue(page.asText().contains( "Configuration page for UnsupportedUnknownParameterValue")); } /** * Creates a new freestyle project and build with a parameter value whose * type is unknown to rebuild plugin. Verify that rebuild succeeds if that * parameter value supports {@link RebuildableParameterValue}. * * @throws Exception * Exception */ public void testRebuildSupportedUnknownParameterValue() throws Exception { WebClient wc = createWebClient(); FreeStyleProject project = createFreeStyleProject(); project.addProperty(new ParametersDefinitionProperty( new SupportedUnknownParameterDefinition("param1", "defaultValue"))); assertBuildStatusSuccess(project .scheduleBuild2(0, new Cause.RemoteCause("host", "note"), new ParametersAction( new SupportedUnknownParameterValue("param1", "value1")))); FreeStyleBuild build = project.getLastBuild(); HtmlPage page = wc.getPage(build, "rebuild"); assertTrue(page.asText(), page.asText().contains("This is a mark for test")); } /** * A parameter value rebuild plugin does not know. */ public static class UnsupportedUnknownParameterValue extends StringParameterValue { private static final long serialVersionUID = 3182218854913929L; public UnsupportedUnknownParameterValue(String name, String value) { super(name, value); } } public static class UnsupportedUnknownParameterDefinition extends StringParameterDefinition { private static final long serialVersionUID = 1014662680565914672L; @DataBoundConstructor public UnsupportedUnknownParameterDefinition(String name, String defaultValue) { super(name, defaultValue); } @Override public ParameterValue createValue(String value) { return new UnsupportedUnknownParameterValue(this.getName(), value); } @Override public StringParameterValue getDefaultParameterValue() { return new UnsupportedUnknownParameterValue(this.getName(), this.getDefaultValue()); } @Extension public static class DescriptorImpl extends ParameterDescriptor { @Override public String getDisplayName() { return "UnsupportedUnknownParameterDefinition"; } } } /** * A parameter value rebuild plugin does not know, but supported by * {@link TestRebuildParameterProvider}. */ public static class SupportedUnknownParameterValue extends StringParameterValue { private static final long serialVersionUID = 114922627975966439L; public SupportedUnknownParameterValue(String name, String value) { super(name, value); } } public static class SupportedUnknownParameterDefinition extends StringParameterDefinition { private static final long serialVersionUID = 1014662680565914672L; @DataBoundConstructor public SupportedUnknownParameterDefinition(String name, String defaultValue) { super(name, defaultValue); } @Override public ParameterValue createValue(String value) { return new SupportedUnknownParameterValue(this.getName(), value); } @Override public StringParameterValue getDefaultParameterValue() { return new SupportedUnknownParameterValue(this.getName(), this.getDefaultValue()); } @Extension public static class DescriptorImpl extends ParameterDescriptor { @Override public String getDisplayName() { return "SupportedUnknownParameterDefinition"; } } } /** * Provides a view for {@link SupportedUnknownParameterValue} when * rebuilding. */ @TestExtension public static class TestRebuildParameterProvider extends RebuildParameterProvider { @Override public RebuildParameterPage getRebuildPage(ParameterValue value) { if (!(value instanceof SupportedUnknownParameterValue)) { return null; } RebuildParameterPage page = new RebuildParameterPage( SupportedUnknownParameterValue.class, "rebuild.groovy"); return page; } } }